home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 176-200 / disk_195 / microemacs / src.zoo / buffer.c < prev    next >
C/C++ Source or Header  |  1989-03-23  |  18KB  |  608 lines

  1. /*  BUFFER.C:   buffer mgmt. routines
  2.         MicroEMACS 3.10
  3.  
  4.  * Buffer management.
  5.  * Some of the functions are internal,
  6.  * and some are actually attached to user
  7.  * keys. Like everyone else, they set hints
  8.  * for the display system.
  9.  */
  10. #include        <stdio.h>
  11. #include    "estruct.h"
  12. #include    "etype.h"
  13. #include        "edef.h"
  14. #include    "elang.h"
  15.  
  16. /*
  17.  * Attach a buffer to a window. The
  18.  * values of dot and mark come from the buffer
  19.  * if the use count is 0. Otherwise, they come
  20.  * from some other window.
  21.  */
  22. PASCAL NEAR usebuffer(f, n)
  23. {
  24.         register BUFFER *bp;    /* temporary buffer pointer */
  25.  
  26.     /* get the buffer name to switch to */
  27.     bp = getdefb();
  28.     bp = getcbuf(TEXT24, bp ? bp->b_bname : "main", TRUE);
  29. /*                          "Use buffer" */
  30.     if (!bp)
  31.         return(ABORT);
  32.  
  33.     /* make it invisable if there is an argument */
  34.     if (f == TRUE)
  35.         bp->b_flag |= BFINVS;
  36.  
  37.     /* switch to it in any case */
  38.     return(swbuffer(bp));
  39. }
  40.  
  41. PASCAL NEAR nextbuffer(f, n)    /* switch to the next buffer in the buffer list */
  42.  
  43. int f, n;    /* default flag, numeric argument */
  44. {
  45.     register BUFFER *bp;    /* current eligable buffer */
  46.     register int status;
  47.  
  48.     /* make sure the arg is legit */
  49.     if (f == FALSE)
  50.         n = 1;
  51.     if (n < 1)
  52.         return(FALSE);
  53.  
  54.     /* cycle thru buffers until n runs out */
  55.     while (n-- > 0) {
  56.         bp = getdefb();
  57.         if (bp == NULL)
  58.             return(FALSE);
  59.         status = swbuffer(bp);
  60.         if (status != TRUE)
  61.             return(status);
  62.     }
  63.     return(status);
  64. }
  65.  
  66. PASCAL NEAR swbuffer(bp)    /* make buffer BP current */
  67.  
  68. BUFFER *bp;
  69.  
  70. {
  71.         register WINDOW *wp;
  72.     register int cmark;        /* current mark */
  73.  
  74.     /* let a user macro get hold of things...if he wants */
  75.     execkey(&exbhook, FALSE, 1);
  76.  
  77.         if (--curbp->b_nwnd == 0) {             /* Last use.            */
  78.                 curbp->b_dotp  = curwp->w_dotp;
  79.                 curbp->b_doto  = curwp->w_doto;
  80.         for (cmark = 0; cmark < NMARKS; cmark++) {
  81.                     curbp->b_markp[cmark] = curwp->w_markp[cmark];
  82.                     curbp->b_marko[cmark] = curwp->w_marko[cmark];
  83.                 }
  84.         curbp->b_fcol  = curwp->w_fcol;
  85.         }
  86.         curbp = bp;                             /* Switch.              */
  87.     if (curbp->b_active != TRUE) {        /* buffer not active yet*/
  88.         /* read it in and activate it */
  89.         readin(curbp->b_fname, TRUE);
  90.         curbp->b_dotp = lforw(curbp->b_linep);
  91.         curbp->b_doto = 0;
  92.         curbp->b_active = TRUE;
  93.     }
  94.         curwp->w_bufp  = bp;
  95.         curwp->w_linep = bp->b_linep;           /* For macros, ignored. */
  96.         curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty.         */
  97.         if (bp->b_nwnd++ == 0) {                /* First use.           */
  98.                 curwp->w_dotp  = bp->b_dotp;
  99.                 curwp->w_doto  = bp->b_doto;
  100.         for (cmark = 0; cmark < NMARKS; cmark++) {
  101.                     curwp->w_markp[cmark] = bp->b_markp[cmark];
  102.                     curwp->w_marko[cmark] = bp->b_marko[cmark];
  103.                 }
  104.         curwp->w_fcol  = bp->b_fcol;
  105.         } else {
  106.         wp = wheadp;            /* Look for old */
  107.             while (wp != NULL) {
  108.                     if (wp!=curwp && wp->w_bufp==bp) {
  109.                             curwp->w_dotp  = wp->w_dotp;
  110.                             curwp->w_doto  = wp->w_doto;
  111.                 for (cmark = 0; cmark < NMARKS; cmark++) {
  112.                                 curwp->w_markp[cmark] = wp->w_markp[cmark];
  113.                                 curwp->w_marko[cmark] = wp->w_marko[cmark];
  114.                             }
  115.                 curwp->w_fcol  = wp->w_fcol;
  116.                             break;
  117.                     }
  118.                     wp = wp->w_wndp;
  119.             }
  120.     }
  121.  
  122.     /* let a user macro get hold of things...if he wants */
  123.     execkey(&bufhook, FALSE, 1);
  124.  
  125.         return(TRUE);
  126. }
  127.  
  128. /*
  129.  * Dispose of a buffer, by name.
  130.  * Ask for the name. Look it up (don't get too
  131.  * upset if it isn't there at all!). Get quite upset
  132.  * if the buffer is being displayed. Clear the buffer (ask
  133.  * if the buffer has been changed). Then free the header
  134.  * line and the buffer header. Bound to "C-X K".
  135.  */
  136. PASCAL NEAR killbuffer(f, n)
  137.  
  138. {
  139.     register BUFFER *bp;    /* ptr to buffer to dump */
  140.  
  141.     /* get the buffer name to kill */
  142.     bp = getdefb();
  143.     bp = getcbuf(TEXT26, bp ? bp->b_bname : "main", TRUE);
  144. /*                   "Kill buffer" */
  145.     if (bp == NULL)
  146.         return(ABORT);
  147.  
  148.     return(zotbuf(bp));
  149. }
  150.  
  151. BUFFER *PASCAL NEAR getdefb()    /* get the default buffer for a use or kill */
  152.  
  153. {
  154.     BUFFER *bp;    /* default buffer */
  155.  
  156.     /* Find the next buffer, which will be the default */
  157.     bp = curbp->b_bufp;
  158.  
  159.     /* cycle through the buffers to find an eligable one */
  160.     while (bp == NULL || bp->b_flag & BFINVS) {
  161.         if (bp == NULL)
  162.             bp = bheadp;
  163.         else
  164.             bp = bp->b_bufp;
  165.  
  166.         /* don't get caught in an infinite loop! */
  167.         if (bp == curbp) {
  168.             bp = NULL;
  169.             break;
  170.         }
  171.     }        
  172.     return(bp);
  173. }
  174.  
  175. PASCAL NEAR zotbuf(bp)    /* kill the buffer pointed to by bp */
  176.  
  177. register BUFFER *bp;
  178.  
  179. {
  180.         register BUFFER *bp1;
  181.         register BUFFER *bp2;
  182.         register int    s;
  183.  
  184.         if (bp->b_nwnd != 0) {                  /* Error if on screen.  */
  185.                 mlwrite(TEXT28);
  186. /*                      "Buffer is being displayed" */
  187.                 return(FALSE);
  188.         }
  189.         if ((s=bclear(bp)) != TRUE)             /* Blow text away.      */
  190.                 return(s);
  191.         free((char *) bp->b_linep);             /* Release header line. */
  192.         bp1 = NULL;                             /* Find the header.     */
  193.         bp2 = bheadp;
  194.         while (bp2 != bp) {
  195.                 bp1 = bp2;
  196.                 bp2 = bp2->b_bufp;
  197.         }
  198.         bp2 = bp2->b_bufp;                      /* Next one in chain.   */
  199.         if (bp1 == NULL)                        /* Unlink it.           */
  200.                 bheadp = bp2;
  201.         else
  202.                 bp1->b_bufp = bp2;
  203.         free((char *) bp);                      /* Release buffer block */
  204.         return(TRUE);
  205. }
  206.  
  207. PASCAL NEAR namebuffer(f,n)    /*    Rename the current buffer    */
  208.  
  209. int f, n;        /* default Flag & Numeric arg */
  210.  
  211. {
  212.     register BUFFER *bp;    /* pointer to scan through all buffers */
  213.     char bufn[NBUFN];    /* buffer to hold buffer name */
  214.  
  215.     /* prompt for and get the new buffer name */
  216. ask:    if (mlreply(TEXT29, bufn, NBUFN) != TRUE)
  217. /*                  "Change buffer name to: " */
  218.         return(FALSE);
  219.  
  220.     /* and check for duplicates */
  221.     bp = bheadp;
  222.     while (bp != NULL) {
  223.         if (bp != curbp) {
  224.             /* if the names the same */
  225.             if (strcmp(bufn, bp->b_bname) == 0)
  226.                 goto ask;  /* try again */
  227.         }
  228.         bp = bp->b_bufp;    /* onward */
  229.     }
  230.  
  231.     strcpy(curbp->b_bname, bufn);    /* copy buffer name to structure */
  232.     curwp->w_flag |= WFMODE;    /* make mode line replot */
  233.     mlerase();
  234.     return(TRUE);
  235. }
  236.  
  237. /*
  238.     List all of the active buffers.  First update the special
  239.     buffer that holds the list.  Next make sure at least 1
  240.     window is displaying the buffer list, splitting the screen
  241.     if this is what it takes.  Lastly, repaint all of the
  242.     windows that are displaying the list.  Bound to "C-X C-B". 
  243.     A numeric argument forces it to list invisable buffers as
  244.     well.
  245. */
  246.  
  247. PASCAL NEAR listbuffers(f, n)
  248. {
  249.         register WINDOW *wp;
  250.         register BUFFER *bp;
  251.         register int    s;
  252.     register int cmark;        /* current mark */
  253.  
  254.         if ((s=makelist(f)) != TRUE)
  255.                 return(s);
  256.         if (blistp->b_nwnd == 0) {              /* Not on screen yet.   */
  257.                 if ((wp=wpopup()) == NULL)
  258.                         return(FALSE);
  259.                 bp = wp->w_bufp;
  260.                 if (--bp->b_nwnd == 0) {
  261.                         bp->b_dotp  = wp->w_dotp;
  262.                         bp->b_doto  = wp->w_doto;
  263.             for (cmark = 0; cmark < NMARKS; cmark++) {
  264.                             bp->b_markp[cmark] = wp->w_markp[cmark];
  265.                             bp->b_marko[cmark] = wp->w_marko[cmark];
  266.                         }
  267.             bp->b_fcol  = wp->w_fcol;
  268.                 }
  269.                 wp->w_bufp  = blistp;
  270.                 ++blistp->b_nwnd;
  271.         }
  272.         wp = wheadp;
  273.         while (wp != NULL) {
  274.                 if (wp->w_bufp == blistp) {
  275.                         wp->w_linep = lforw(blistp->b_linep);
  276.                         wp->w_dotp  = lforw(blistp->b_linep);
  277.                         wp->w_doto  = 0;
  278.             for (cmark = 0; cmark < NMARKS; cmark++) {
  279.                             wp->w_markp[cmark] = NULL;
  280.                             wp->w_marko[cmark] = 0;
  281.                     }
  282.                         wp->w_flag |= WFMODE|WFHARD;
  283.                 }
  284.                 wp = wp->w_wndp;
  285.         }
  286.         return(TRUE);
  287. }
  288.  
  289. /*
  290.  * This routine rebuilds the
  291.  * text in the special secret buffer
  292.  * that holds the buffer list. It is called
  293.  * by the list buffers command. Return TRUE
  294.  * if everything works. Return FALSE if there
  295.  * is an error (if there is no memory). Iflag
  296.  * indecates weather to list hidden buffers.
  297.  */
  298. PASCAL NEAR makelist(iflag)
  299.  
  300. int iflag;    /* list hidden buffer flag */
  301.  
  302. {
  303.         register char   *cp1;
  304.         register char   *cp2;
  305.         register int    c;
  306.         register BUFFER *bp;
  307.         register LINE   *lp;
  308.         register int    s;
  309.     register int    i;
  310.         long nbytes;        /* # of bytes in current buffer */
  311.         char b[7+1];
  312.         char line[128];
  313.  
  314.         blistp->b_flag &= ~BFCHG;               /* Don't complain!      */
  315.         if ((s=bclear(blistp)) != TRUE)         /* Blow old text away   */
  316.                 return(s);
  317.         strcpy(blistp->b_fname, "");
  318.         if (addline(TEXT30) == FALSE
  319. /*                  "ACT   Modes      Size Buffer          File" */
  320.         ||  addline("--- --------- ------- --------------- ----") == FALSE)
  321.                 return(FALSE);
  322.         bp = bheadp;                            /* For all buffers      */
  323.  
  324.     /* build line to report global mode settings */
  325.     cp1 = &line[0];
  326.     *cp1++ = ' ';
  327.     *cp1++ = ' ';
  328.     *cp1++ = ' ';
  329.     *cp1++ = ' ';
  330.  
  331.     /* output the mode codes */
  332.     for (i = 0; i < NUMMODES; i++)
  333.         if (gmode & (1 << i))
  334.             *cp1++ = modecode[i];
  335.         else
  336.             *cp1++ = '.';
  337.     strcpy(cp1, TEXT31);
  338. /*                  "         Global Modes" */
  339.     if (addline(line) == FALSE)
  340.         return(FALSE);
  341.  
  342.     /* output the list of buffers */
  343.         while (bp != NULL) {
  344.         /* skip invisable buffers if iflag is false */
  345.                 if (((bp->b_flag&BFINVS) != 0) && (iflag != TRUE)) {
  346.                         bp = bp->b_bufp;
  347.                         continue;
  348.                 }
  349.                 cp1 = &line[0];                 /* Start at left edge   */
  350.  
  351.         /* output status of ACTIVE flag (has the file been read in? */
  352.                 if (bp->b_active == TRUE)    /* "@" if activated       */
  353.                         *cp1++ = '@';
  354.                 else
  355.                         *cp1++ = ' ';
  356.  
  357.         /* output status of changed flag */
  358.                 if ((bp->b_flag&BFCHG) != 0)    /* "*" if changed       */
  359.                         *cp1++ = '*';
  360.                 else
  361.                         *cp1++ = ' ';
  362.  
  363.         /* report if the file is truncated */
  364.                 if ((bp->b_flag&BFTRUNC) != 0)
  365.                         *cp1++ = '#';
  366.                 else
  367.                         *cp1++ = ' ';
  368.  
  369.                 *cp1++ = ' ';    /* space */
  370.  
  371.         /* output the mode codes */
  372.         for (i = 0; i < NUMMODES; i++) {
  373.             if (bp->b_mode & (1 << i))
  374.                 *cp1++ = modecode[i];
  375.             else
  376.                 *cp1++ = '.';
  377.         }
  378.                 *cp1++ = ' ';                   /* Gap.                 */
  379.                 nbytes = 0L;                    /* Count bytes in buf.  */
  380.                 lp = lforw(bp->b_linep);
  381.                 while (lp != bp->b_linep) {
  382.                         nbytes += (long)llength(lp)+1L;
  383.                         lp = lforw(lp);
  384.                 }
  385.                 long_asc(b, 7, nbytes);             /* 6 digit buffer size. */
  386.                 cp2 = &b[0];
  387.                 while ((c = *cp2++) != 0)
  388.                         *cp1++ = c;
  389.                 *cp1++ = ' ';                   /* Gap.                 */
  390.                 cp2 = &bp->b_bname[0];          /* Buffer name          */
  391.                 while ((c = *cp2++) != 0)
  392.                         *cp1++ = c;
  393.                 *cp1++ = ' ';                   /* Gap.                 */
  394.                 cp2 = &bp->b_fname[0];          /* File name            */
  395.                 if (*cp2 != 0) {
  396.                         while (cp1 < &line[22+NBUFN])
  397.                                 *cp1++ = ' ';
  398.                         while ((c = *cp2++) != 0) {
  399.                                 if (cp1 < &line[128-1])
  400.                                         *cp1++ = c;
  401.                         }
  402.                 }
  403.                 *cp1 = 0;                       /* Add to the buffer.   */
  404.                 if (addline(line) == FALSE)
  405.                         return(FALSE);
  406.                 bp = bp->b_bufp;
  407.         }
  408.         return(TRUE);                          /* All done             */
  409. }
  410.  
  411. /* Translate a long to ascii form. Don't trust various systems
  412.    ltoa() routines.. they aren't consistand                */
  413.  
  414. PASCAL NEAR long_asc(buf, width, num)
  415.  
  416. char   buf[];
  417. int    width;
  418. long   num;
  419.  
  420. {
  421.         buf[width] = 0;                         /* End of string.       */
  422.         while (num >= 10) {                     /* Conditional digits.  */
  423.                 buf[--width] = (int)(num%10L) + '0';
  424.                 num /= 10L;
  425.         }
  426.         buf[--width] = (int)num + '0';          /* Always 1 digit.      */
  427.         while (width != 0)                      /* Pad with blanks.     */
  428.                 buf[--width] = ' ';
  429. }
  430.  
  431. /*
  432.  * The argument "text" points to
  433.  * a string. Append this line to the
  434.  * buffer list buffer. Handcraft the EOL
  435.  * on the end. Return TRUE if it worked and
  436.  * FALSE if you ran out of room.
  437.  */
  438. PASCAL NEAR addline(text)
  439. char    *text;
  440. {
  441.         register LINE   *lp;
  442.         register int    i;
  443.         register int    ntext;
  444.  
  445.         ntext = strlen(text);
  446.         if ((lp=lalloc(ntext)) == NULL)
  447.                 return(FALSE);
  448.         for (i=0; i<ntext; ++i)
  449.                 lputc(lp, i, text[i]);
  450.         blistp->b_linep->l_bp->l_fp = lp;       /* Hook onto the end    */
  451.         lp->l_bp = blistp->b_linep->l_bp;
  452.         blistp->b_linep->l_bp = lp;
  453.         lp->l_fp = blistp->b_linep;
  454.         if (blistp->b_dotp == blistp->b_linep)  /* If "." is at the end */
  455.                 blistp->b_dotp = lp;            /* move it to new line  */
  456.         return(TRUE);
  457. }
  458.  
  459. /*
  460.  * Look through the list of
  461.  * buffers. Return TRUE if there
  462.  * are any changed buffers. Buffers
  463.  * that hold magic internal stuff are
  464.  * not considered; who cares if the
  465.  * list of buffer names is hacked.
  466.  * Return FALSE if no buffers
  467.  * have been changed.
  468.  */
  469. PASCAL NEAR anycb()
  470. {
  471.         register BUFFER *bp;
  472.  
  473.         bp = bheadp;
  474.         while (bp != NULL) {
  475.                 if ((bp->b_flag&BFINVS)==0 && (bp->b_flag&BFCHG)!=0)
  476.                         return(TRUE);
  477.                 bp = bp->b_bufp;
  478.         }
  479.         return(FALSE);
  480. }
  481.  
  482. /*
  483.  * Find a buffer, by name. Return a pointer
  484.  * to the BUFFER structure associated with it.
  485.  * If the buffer is not found
  486.  * and the "cflag" is TRUE, create it. The "bflag" is
  487.  * the settings for the flags in in buffer.
  488.  */
  489. BUFFER *PASCAL NEAR bfind(bname, cflag, bflag)
  490.  
  491. register char   *bname;    /* name of buffer to find */
  492. int cflag;        /* create it if not found? */
  493. int bflag;        /* bit settings for a new buffer */
  494.  
  495. {
  496.         register BUFFER *bp;
  497.     register BUFFER *sb;    /* buffer to insert after */
  498.         register LINE   *lp;
  499.     int cmark;        /* current mark */
  500.  
  501.         bp = bheadp;
  502.         while (bp != NULL) {
  503.                 if (strcmp(bname, bp->b_bname) == 0)
  504.                         return(bp);
  505.                 bp = bp->b_bufp;
  506.         }
  507.         if (cflag != FALSE) {
  508.                 if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL)
  509.                         return(NULL);
  510.                 if ((lp=lalloc(0)) == NULL) {
  511.                         free((char *) bp);
  512.                         return(NULL);
  513.                 }
  514.         /* find the place in the list to insert this buffer */
  515.         if (bheadp == NULL || strcmp(bheadp->b_bname, bname) > 0) {
  516.             /* insert at the beginning */
  517.                     bp->b_bufp = bheadp;
  518.                     bheadp = bp;
  519.             } else {
  520.             sb = bheadp;
  521.             while (sb->b_bufp != NULL) {
  522.                 if (strcmp(sb->b_bufp->b_bname, bname) > 0)
  523.                     break;
  524.                 sb = sb->b_bufp;
  525.             }
  526.  
  527.             /* and insert it */
  528.                    bp->b_bufp = sb->b_bufp;
  529.                 sb->b_bufp = bp;
  530.                }
  531.  
  532.         /* and set up the other buffer fields */
  533.         bp->b_topline = NULL;
  534.         bp->b_botline = NULL;
  535.         bp->b_active = TRUE;
  536.                 bp->b_dotp  = lp;
  537.                 bp->b_doto  = 0;
  538.         for (cmark = 0; cmark < NMARKS; cmark++) {
  539.                     bp->b_markp[cmark] = NULL;
  540.                     bp->b_marko[cmark] = 0;
  541.                 }
  542.         bp->b_fcol = 0;
  543.                 bp->b_flag  = bflag;
  544.         bp->b_mode  = gmode;
  545.                 bp->b_nwnd  = 0;
  546.                 bp->b_linep = lp;
  547.                 strcpy(bp->b_fname, "");
  548.                 strcpy(bp->b_bname, bname);
  549. #if    CRYPT
  550.         bp->b_key[0] = 0;
  551. #endif
  552.                 lp->l_fp = lp;
  553.                 lp->l_bp = lp;
  554.         }
  555.         return(bp);
  556. }
  557.  
  558. /*
  559.  * This routine blows away all of the text
  560.  * in a buffer. If the buffer is marked as changed
  561.  * then we ask if it is ok to blow it away; this is
  562.  * to save the user the grief of losing text. The
  563.  * window chain is nearly always wrong if this gets
  564.  * called; the caller must arrange for the updates
  565.  * that are required. Return TRUE if everything
  566.  * looks good.
  567.  */
  568. PASCAL NEAR bclear(bp)
  569. register BUFFER *bp;
  570. {
  571.         register LINE   *lp;
  572.         register int    s;
  573.     int cmark;        /* current mark */
  574.  
  575.         if ((bp->b_flag&BFINVS) == 0            /* Not scratch buffer.  */
  576.         && (bp->b_flag&BFCHG) != 0              /* Something changed    */
  577.         && (s=mlyesno(TEXT32)) != TRUE)
  578. /*                    "Discard changes" */
  579.                 return(s);
  580.         bp->b_flag  &= ~BFCHG;                  /* Not changed          */
  581.         while ((lp=lforw(bp->b_linep)) != bp->b_linep)
  582.                 lfree(lp);
  583.         bp->b_dotp  = bp->b_linep;              /* Fix "."              */
  584.         bp->b_doto  = 0;
  585.     for (cmark = 0; cmark < NMARKS; cmark++) {
  586.             bp->b_markp[cmark] = NULL;  /* Invalidate "mark"    */
  587.             bp->b_marko[cmark] = 0;
  588.         }
  589.     bp->b_fcol = 0;
  590.         return(TRUE);
  591. }
  592.  
  593. PASCAL NEAR unmark(f, n)    /* unmark the current buffers change flag */
  594.  
  595. int f, n;    /* unused command arguments */
  596.  
  597. {
  598.     register WINDOW *wp;
  599.  
  600.     /* unmark the buffer */
  601.     curbp->b_flag &= ~BFCHG;
  602.  
  603.     /* unmark all windows as well */
  604.     upmode();
  605.  
  606.     return(TRUE);
  607. }
  608.